<?php
/*
                   _ooOoo_
                  o8888888o
                  88" . "88
                  (| -_- |)
                  O\  =  /O
               ____/`---'\____
             .'  \\|     |//  `.
            /  \\|||  :  |||//  \
           /  _||||| -:- |||||-  \
           |   | \\\  -  /// |   |
           | \_|  ''\---/''  |   |
           \  .-\__  `-`  ___/-. /
         ___`. .'  /--.--\  `. . __
      ."" '<  `.___\_<|>_/___.'  >'"".
     | | :  `- \`.;`\ _ /`;.`/ - ` : | |
     \  \ `-.   \_ __\ /__ _/   .-` /  /
======`-.____`-.___\_____/___.-`____.-'======
                   `=---='
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
         佛祖保佑       永无BUG
*/
/**
 * 自定义函数
 * @author huanran.zhao
 * @since 2012-11-26
 */
class My {
    private static $GB2260;
    private static $cache = array();
    /**
     * 实例化
     * @return my
     */
    public static function getInstance(){
        $my = new My();
        return $my;
    }

    /**
     * 唯一名称 得到 数据列表
     * @例 My::item2list('datas','product',array('publish'=>1,'order'=>'hot','page'=>1,'pagesize'=>10));
     * @param string $table 表名
     * @param string $item 唯一名称
     * @param array $param.order 排序方式(默认最新) -> hot:推荐
     *              $param.page 当前页数(默认为1)
     *              $param.pagesize 每页条数(需要分页时,该参数必填)
     *              $param.publish 发布状态(值:1/0)(默认全部)
     *              $param.field 表字段(多个逗号分隔)
     */
    public static function item2list($table='',$item='',$param=''){
        if(!My::is_table($table))
            return -1;
        if(!My::is_item($item))
            return -2;
        $where = "`item`='{$item}' ";
        //order排序
        if(My::arr2var($param,'order')=='hot'){
            $order = "hot DESC,ordering ASC,adddate DESC";
        }else{
            $order = "ordering ASC,adddate DESC,id DESC";
        }
        //分页
        if(My::is_id(My::arr2var($param,'pagesize'))){
            $pagesize = My::arr2var($param,'pagesize');
            $page = (int)My::arr2var($param,'page');
            if(!My::is_id($page))
                $page = 1;
            $limit = (($page-1)*$pagesize).",".$pagesize;
        }else{
            $limit = '';
        }
        //publish
        if(isset($param['publish']) AND $param['publish']==1)
            $where .= "AND `publish`=1";
        elseif(isset($param['publish']) AND $param['publish']==0)
            $where .= "AND `publish`=0";
        //where
        if(!empty($param['where'])){
            $where .= ' '.$param['where'];
        }
        //field
        $field = !empty($param['field'])?$param['field']:'*';
        //cache
        $cacheId = 'My_item2list'.$table.$item.My::encodeJson($param);
        $result=My::getCache($cacheId,array('pre'=>$table));
        //result
        if($result==''){
            $result = DB($table)->field($field)->where($where)->order($order)->limit($limit)->cache()->select();
            if(is_array($result))
            foreach($result as &$value){
                if(isset($value['params']))
                    $value['params'] = My::decodeJson($value['params']);
                if(isset($value['content']))
                    $value['content'] = My::decodeHtml($value['content']);
            }
            if($result=='') $result = 'cacheNull';//值为空时,置为字符串null,否则缓存不起作用
            My::setCache($cacheId,$result,array('pre'=>$table));
        }
        if($result=='cacheNull') $result = '';//恢复空值
        return $result;
    }

    /**
     * 更新表中的某个字段的值
     * @例 My::setField('datas',$id,array('key'=>'params.name','value'=>1));
     * @param string $table 表名
     * @param int $id 数据id
     * @param string $param.key 字段名
     * @param string $param.value 值(可以数组)
     * @param string $param.item 唯一名称(如:member/daily...)<强烈建议带上该参数><匹配数据,防止出错>
     * @return $return['old']:旧值 $return['new']:新值
     */
    public static function setField($table='',$id=0,$param=''){
        if(!My::is_id($id)) return -1;
        if(!My::is_var($table)) return -2;
        //判断参数:字段名称是否正确
        if(empty($param['key']))
            return -3;
        //没有value变量值
        if(!isset($param['value']))
            return -4;
        //result
        $result = DB($table)->where("id={$id}")->find();
        //找不到数据
        if(!$result)
            return -5;
        //params字段
        if(substr($param['key'],0,7)=='params.'){
            $param['key'] = substr($param['key'],7);//去除头部分(params.)
            if(!My::is_var($param['key']))//判断字段名格式是否正确
                return -9;
            if($result)
                $result['params'] = isset($result['params'])?My::decodeJson($result['params']):'';
            //记录数据的前后内容
            $return['old'] = isset($result['params'][$param['key']])?$result['params'][$param['key']]:'';
            $return['new'] = $param['value'];
            //判断item类型是否匹配(表中也要有item字段才行)
            if(isset($param['item']) AND isset($result['item']) AND $param['item']!=$result['item'])//要传参item和表中的item都存在时才比较,否则略过
                return -6;
            $result['params'][$param['key']] = $param['value'];
            DB($table)->where("id={$id}")->clear()->save(array('params'=>$result['params']));
            My::setParams($table,$result['params'],$id,isset($param['item'])?$param['item']:'');
        }
        //主表字段
        else{
            if(!My::is_var($param['key']) OR !array_key_exists($param['key'],$result))//字段名格式错误 OR 主表中不存在该字段时
                return -7;
            //记录数据的前后内容
            $return['old'] = isset($result[$param['key']])?$result[$param['key']]:'';
            $return['new'] = $param['value'];
            //判断item类型是否匹配(表中也要有item字段才行)
            if(isset($param['item']) AND isset($result['item']) AND $param['item']!=$result['item'])//要传参item和表中的item都存在时才比较,否则略过
                return -8;
            DB($table)->where("id={$id}")->clear()->save(array($param['key']=>$param['value']));
        }
        return $return;
    }

    /**
     * ID->得到字段值
     * @param string $table 表
     * @param int $id ID
     * @param string $field 字段名(如:title / params.name)
     */
    public static function id2field($table='',$id=0,$field=''){
        if(!My::is_id($id)) return -1;
        if(empty($field)) return -2;
        if(!My::is_var($table)) return -3;
        //cache
        $cacheId = 'My_id2field'.$table.$id.$field;
        $result = My::getCache($cacheId,array('pre'=>$table));
        //result
        if($result==''){
            $result = DB($table)->where("id={$id}")->cache()->find();
            if(!$result)
                return false;
            if($field=='content')
                $result['content'] = My::decodeHtml($result['content']);
            if(strlen($field)>=6 AND substr($field,0,6)=='params')
                $result['params'] = My::decodeJson($result['params']);
            $result = My::arr2var($result,$field);
            if($result=='') $result = 'cacheNull';//值为空时,置为字符串null,否则缓存不起作用
            My::setCache($cacheId,$result,array('pre'=>$table));
        }
        if($result=='cacheNull') $result = '';//恢复空值
        return $result;
    }
    //此函数的item命名要注意再研究一下是否合理
    public static function item2field($table='',$item='',$field=''){
        $cat_id = M('admin.category')->item2id($item);
        $result = My::id2field($table,$cat_id,$field);
        return $result;
    }

    /**
     * ID->详细
     * @param string $table 表
     * @param int $id 数据ID
     * @param array $param.has_page 值:true/false -> 是否要读取上一篇/下一篇信息
     * @param array $param.where where条件 (注意前边不需要AND)
     * @param array $param.publish publish条件（仅当值为‘1’或‘0’时有效）
     */
    public static function id2detail($table='', $id=0, $param=''){
        if(!My::is_id($id)) return -1;
        if(!My::is_var($table)) return -2;
        //cache
        $cacheId = 'My_id2detail'.$table.$id.My::encodeJson($param);
        $result = My::getCache($cacheId,array('pre'=>$table));
        if($result==''){
            //sql WHERE条件
            $where = My::arr2var($param,'where','1 ');
            //publish的where条件
            if(in_array(My::arr2var($param,'publish'),array('0','1')))
                $where .= "AND publish={$param['publish']} ";
            //result
            $result = DB($table)->where("id={$id} AND {$where}")->cache()->find();
            //echo DB('')->getLastSql();
            if(!$result)
                return -3;
            if(isset($result['params']))
                $result['params'] = My::decodeJson($result['params']);
            if(isset($result['content']))
                $result['content'] = My::decodeHtml($result['content']);
            //上一篇 / 下一篇
            if(My::arr2var($param,'has_page')===true AND $result){
                //上一篇
                $result['prev']  = DB('datas')->field('id,title')->where("((`ordering`={$result['ordering']} AND `adddate`='{$result['adddate']}' AND `id`>{$result['id']}) OR (`ordering`={$result['ordering']} AND `adddate`>'{$result['adddate']}') OR (`ordering`<{$result['ordering']})) AND (`id`<{$id} OR `id`>{$id}) AND `item`='{$result['item']}' AND publish=1")->order("ordering DESC,adddate ASC,id ASC")->limit('0,1')->cache()->find();;
                //下一篇
                $result['next']  = DB('datas')->field('id,title')->where("((`ordering`={$result['ordering']} AND `adddate`='{$result['adddate']}' AND `id`<{$result['id']}) OR (`ordering`={$result['ordering']} AND `adddate`<'{$result['adddate']}') OR (`ordering`>{$result['ordering']})) AND (`id`<{$id} OR `id`>{$id}) AND `item`='{$result['item']}' AND publish=1")->order("ordering ASC,adddate DESC,id DESC")->limit('0,1')->cache()->find();;
                //echo DB('')->getLastSql();
            }
            if($result=='') $result = 'cacheNull';//值为空时,置为字符串null,否则缓存不起作用
            My::setCache($cacheId,$result,array('pre'=>$table));
        }
        if($result=='cacheNull') $result = '';//恢复空值
        return $result;
    }
    public static function alias2detail($table='', $alias='', $param=''){
        if(!My::is_var($alias)) return -1;
        if(!My::is_var($table)) return -2;
        $id = DB($table)->where("`alias`='{$alias}'")->cache()->getField('id');
        if(!My::is_id($id)) return -3;
        return My::id2detail($table,$id,$param);
    }
    public static function alias2field($table='', $alias='', $field=''){
        $result = My::alias2detail($table,$alias);
        $result = empty($result['publish'])?'':My::arr2var($result,$field);
        return $result;
    }

    /**
     * 字段值加/减运算
     * @param string $table 表
     * @param int $id 数据ID
     * @param string $param.key 字段名(如:title/params.ID)
     * @param string $param.value 字段值(数值,正负数均可)
     * @param string $param.type params表类型属性(如:member/daily...)<强烈建议带上该参数>
     * @param string $param.kind 运算类型(+-/*)<默认为+>
     */
    public static function mathField($table='',$id=0,$param=''){
        if(!My::is_id($id)) return -1;
        if(!My::is_var($table)) return -2;
        if(!isset($param['key'])) return -3;
        if(!isset($param['value'])) return -4;
        $result = My::id2detail($table,$id);
        if(!is_array($result))  return -5;
        //params参数字段时
        if(substr($param['key'],0,7)=='params.'){
            $key = str_replace('params.','',$param['key']);
            $result['params'][$key] = My::arr2var($result,"params.{$key}",0);
            //+-*/运算
            if(isset($param['kind']) AND $param['kind']=='-')
                $result['params'][$key] = (float)$result['params'][$key]-(float)$param['value'];
            elseif(isset($param['kind']) AND $param['kind']=='*')
                $result['params'][$key] = (float)$result['params'][$key]*(float)$param['value'];
            elseif(isset($param['kind']) AND $param['kind']=='/')
                $result['params'][$key] = (float)$result['params'][$key]/(float)$param['value'];
            else
                $result['params'][$key] = (float)$result['params'][$key]+(float)$param['value'];
            //保存入库
            $ok = DB($table)->where("id={$id}")->clear()->save(array('params'=>$result['params']));
            if($ok){
                $type = isset($param['type'])?$param['type']:'';
                My::setParams($table,$result['params'],$id,$type);
                return true;
            }else{
                return -6;
            }
        }else{
            if(!isset($result[$param['key']]))
                return -7;
            //+-*/运算
            if(isset($param['kind']) AND $param['kind']=='-')
                $result[$param['key']] = (float)$result[$param['key']]-(float)$param['value'];
            elseif(isset($param['kind']) AND $param['kind']=='*')
                $result[$param['key']] = (float)$result[$param['key']]*(float)$param['value'];
            elseif(isset($param['kind']) AND $param['kind']=='/')
                $result[$param['key']] = (float)$result[$param['key']]/(float)$param['value'];
            else
                $result[$param['key']] = (float)$result[$param['key']]+(float)$param['value'];
            //保存入库
            $ok = DB($table)->where("id={$id}")->clear()->save(array($param['key']=>$result[$param['key']]));
            if($ok){
                return true;
            }else
                return -8;
        }
    }

    /**
     * 将$A数组的键值替换为$B数组的键值(按顺序从前到后面替换)
     * @param array $A 要替换键值的源数组
     * @param array $B 取其数组中的键值
     */
    public static function array_change_key($A,$B){
        if(is_array($A) AND is_array($B)){
            foreach($A as $key=>$value){
                $kkk = key($B);
                $kkk = "['".str_replace(".", "']['", $kkk)."']";
                eval("\$result{$kkk} = '{$value}';");
                next($B);
            }
        }else{
            $result = $A;
        }
        return $result;
    }

    /**
     * 得到一个数组的总和(一维/多维)
     * @param array $arr 要统计数组
     * @param array $field 要统计字段名(为空时统计一维数组的和)<多维时的参数方法:params.money>
     */
    public static function sums($arr,$field=""){
        $result = 0;
        if(is_array($arr)){
            //字段为空时,统计一维数组的和
            if(!$field){
                $result = array_sum($arr);
            }
            //字段不为空
            else{
                $field = '["'.str_replace('.','"]["',$field).'"]';
                //echo $field;
                foreach($arr as $value){
                    $temp = 0;
                    @eval('$temp=$value'.$field.';');
                    if(is_numeric($temp))
                        $result += $temp;
                }
            }
        }
        return $result;
    }

    /**
     * 得到缓存
     * @param string $item 缓存唯一名称(可以是数组)
     * @param array $param['pre'] 缓存文件前缀
     */
    public static function getCache($item, $param=''){
        //item为数组时,md5作为唯一名
        if(is_array($item))
            $item = md5(serialize($item));
        //缓存前缀
        $pre = My::arr2var($param,'pre');
        //得到缓存
        return S($item, array('pre'=>$pre));
    }
    /**
     * 设置缓存
     * @param string $item 缓存唯一名称(可以是数组)
     * @param array $arr 数组
     * @param array $param['pre'] 缓存文件前缀
     */
    public static function setCache($item, $arr, $param=''){
        //item为数组时,md5作为唯一名
        if(is_array($item))
            $item = md5(serialize($item));
        //缓存前缀
        $pre = My::arr2var($param,'pre');
        //设置缓存
        return S($item, $arr, array('pre'=>$pre));
    }

    /**
     * 序列化（已废弃）
     */
    public static function serialize($arr=''){
        if(empty($arr) OR !is_array($arr)) return '';
        $result = serialize($arr);
        return $result;
    }
    /**
     * 反序列化（已废弃）
     * @param string $str 序列化字符串
     * @param boolean $is_escape 是否加密html(防止单双引号在模板html中干扰报错)
     */
    public static function unserialize($str='',$is_escape=false){
        if(empty($str)) return '';
        if(is_array($str)) return $str;
        //刚从数据库里读出来的"引号有被加密,需要解密
        $str_ = htmlspecialchars_decode($str, ENT_QUOTES);
        $result = @unserialize($str_);//解码的是 解密过引号的串
        //为空时,再次尝试解码非解密过引号的串
        if(empty($result))
            $result = @unserialize($str);
        if(empty($result))
            $result = @unserialize(self::decodeHtml($str));
        //数组里边的"\等字符在input框的value里会显示不正常,所以对数字元素进行加密
        if($is_escape===true){
            $result = htmlEscape($result);
        }
        //print_r($result);exit;
        return $result;
    }
    
    /*********params操作 S**********/
    /**
     * 设置表中某个id的参数(处理整个大数组参数的添加,如需要只更新params中的某个字段请用updateParams函数)
     * @param string $table 主表名
     * @param array $data 数据数组
     * @param int $idid 主表ID
     * @param int $type 类型(表单模型的分类item值或cat_id)
     * @return bool
     */
    public static function setParams($table,$data,$idid,$type=''){
        if(!My::is_id($idid)) return -1;
        //echo '<pre>';print_r($data);exit;
        if(is_array($data)){
            //将多维数组转换为一维
            $data = self::array_multiple2single($data);
            //根据$type表单模型名称,获得索引字段
            $indexing = Form::getIndexing($type);
            if(!is_array($indexing))    $indexing = array();
            //print_r($indexing);exit;
            //获取params副表中的原有数据
            $old = My::getParams($table,$idid);
            //var_dump($old);exit;
            //foreach
            foreach($data as $key=>$value){
                list($key_pre)=explode('.',$key);
                //非索引字段时,略过
                if(!in_array($key_pre,$indexing)) continue;
                //值为数组时,序列化 (因上面已经转换为一维self::array_multiple2single($data);所以不会出现数组的情况,以下这句可以忽略)
                if(is_array($value)) { $value = My::array_filter($value);}
                //addData
                $addData['key'] = $key;
                $addData['value'] = $value;
                $addData['idid'] = $idid;
                $addData['type'] = $type;
                $addData['adddate'] = time();
                $addData['author'] = My::user('username');
                //如果原数据$old中已存在$key变量,而且值相等,则略过continue
                if(is_array($old) AND array_key_exists($key,$old) AND $old[$key]==$value)
                    continue;
                //如果原数据$old中已存在$key变量,且值不相等则replace
                elseif(is_array($old) AND array_key_exists($key,$old) AND $old[$key]!=$value)
                    DB($table.'_params')->where("`key`='{$key}' AND `idid`='{$idid}'")->add($addData,'',true);//replace
                //如果原数据$old中不存在$key变量,则新增
                elseif(!isset($old[$key]))
                    DB($table.'_params')->add($addData);
            }
            //如果旧数据$old中已存在$key变量,而新数据$data中没有该变量,则删除
            if(is_array($old))
            foreach($old as $key=>$value){
                if(!isset($data[$key])){
                    DB($table.'_params')->where("`key`='{$key}' AND `idid`='{$idid}'")->delete();
                }
            }
        }
    }
    /**
     * 得到表中某个id的所有参数
     * @param string $table 主表名
     * @param int $idid 主表ID
     * @return array
     */
    public static function getParams($table='',$idid=0){
        if(!My::is_id($idid)) return -1;
        if(!My::is_var($table)) return -2;
        $result = DB($table.'_params')->where("`idid`={$idid}")->select();
        if(is_array($result))
        foreach($result as $key=>$value){
            $list[$value['key']]=$value['value'];
        }
        return isset($list)?$list:array();
    }
    /**
     * 删除参数
     * @param string $table 表
     * @param int $idid ID
     */
    public static function deleteParams($table='',$idid=0){
        if(!My::is_id($idid)) return -1;
        if(!My::is_var($table)) return -2;
        $result = DB($table.'_params')->where("`idid`={$idid}")->delete();
        return $result;
    }
    /**
     * 得到要保留指定原来参数(params参数->字段白名单)
     * <注:该函数只用于主表中的params字段,与副表中的params表无关>
     * <注:只是得到一个新的数组而已,没有操作更改数据库中的params参数>
     * @例: My::keepParams($_POST['params'],array('table'=>'datas','id'=>$id,'field'=>'id,title'));//field和verifyId二选一
     * @param array $newparams 新参数数组
     * @param string $param.table 主表名
     *        int    $param.id 主表数据id
     *        string $param.verifyId 表单验证(表单验证的分类id 或 唯一名称item) <verifyId和field二选一,verifyId优先级高于field>
     *        string $param.field 要保留的params参数字段列表,用逗号分隔(如:'id,title') <verifyId和field二选一,verifyId优先级高于field>
     * @return array 新数组
     */
    public static function keepParams($newparams='',$param=''){
        $id = isset($param['id'])?(int)$param['id']:0;
        if(!My::is_id($id)) return -1;
        $table = isset($param['table'])?$param['table']:'';
        if(!My::is_var($table)) return -2;
        $params = DB($table)->where("id={$id}")->getField('params');
        if($params!='')
            $params = My::decodeJson($params);
        //旧params数据为空,直接返回新数组
        if(!$params OR !is_array($params))
            return $newparams;
        //确定白名单字段
        if(!empty($param['verifyId'])){//从表单模型中获取白名单字段
            $fields = Form::getWhite($param['verifyId']);
        }elseif(!empty($param['field'])){//获取函数参数中的field值作为白名单字段
            $fields = explode(',',$param['field']);
        }else{
            return $newparams;
        }
        //生成新数组
        if(is_array($fields))
        foreach($fields as $value){
            //表里面的旧$params参数存在该白名单字段,而且新数据$newparams中不存在该白名单字段时, 才进行白名单值保护
            if(isset($params[$value]) AND !isset($newparams[$value]))
                $newparams[$value] = $params[$value];
        }
        return $newparams;
    }
    
    /**
     * 数组组合(将多维数组转换为一维)
     */
    public static function array_multiple2single($array){
        if(!function_exists('myfunction')){
            function myfunction($array,$pre='',&$tempResult){
                if(is_array($array)){
                    $pre = ($pre!='')?$pre.'.':'';
                    foreach($array as $key=>$value){
                        if(is_array($value)){
                            myfunction($value,$pre.$key,$tempResult);
                        }
                        else{
                            $tempResult["{$pre}{$key}"]=$value;
                        }
                    }
                }else{
                    $tempResult["{$pre}{$key}"]=$value;
                }
            }
        }
        $tempResult = array();
        $result = myfunction($array,'',$tempResult);
        return $tempResult;
    }
    
    /**
     * 生成写入模板
     * @param string/array $content 内容
     * @return string $path 路径(DATA_DIR.'1.png')
     */
    public static function write($content,$path){
        $dir = dirname($path);
        if(!is_dir($dir)) mk_dir($dir);
        $fp = fopen($path,"w");
        fwrite($fp,$content);
        fclose($fp);
    }
    
    /**
     * 解码html
     * @param string $str
     * @return string
     */
    public static function decodeHtml($str=''){
        if(empty($str) OR !is_string($str)) return $str;
        $str = htmlspecialchars_decode($str, ENT_QUOTES);
        //将图片路径的{__PUB__}字符串替换成真实路径
        $str = My::decodeImg($str);
        return $str;
    }
    /**
     * 加密html
     * @param string $str
     * @param boolean $dealImage 是否My::encodeImg()处理图片 (true/false默认false)
     * @return string
     */
    public static function encodeHtml($str='', $dealImage=false){
        if(empty($str) OR !is_string($str)) return $str;
        //先decodeHtml
        $str = My::decodeHtml($str);
        //把ueditor上传的文件从临时目录移动指定的地方
        $str = My::dealUeditor($str);
        //将图片路径的真实路径替换为{__PUB__}字符串 / 将图片的二进制数据另存为图片
        if($dealImage)
            $str = My::encodeImg($str);
        return htmlspecialchars($str,ENT_QUOTES);
    }
    
    /**
     * 去除html空格与换行
     * @param string $content 源代码内容
     */
    public static function html_strip_space($content=''){
        if(!empty($content)){
            $find = array("~>\s+<~", "~>(\s+\r|\n|\r\n)~", "/<!--[^!]*-->/i", '/\/\*[^*]*\*\//i', '#\t#');
            $replace = array('><', '>', '', '', '');
            $content = preg_replace($find, $replace, $content);
        }
        return $content;
    }

    /**
     * 删除数据库缓存
     * @param string name 数据表名(不包含前缀)
     */
    public static function clear($name=''){
        //删除指定前缀的缓存文件
        if($name!=''){
            $files = glob(DATA_DIR."Cache/__{$name}__*");
            if(is_array($files))
            foreach($files as $v){
                if(file_exists($v))  unlink($v);
            }
        }
        //删除整个Cache文件夹
        else{
            @rm_dir(DATA_DIR.'Cache');
        }
    }

    /**
     * 自定义对数组进行排序
     * @param string $arr 数据数组(数据库读出来的一条数据数组)
     * @param string $orderArr 自定义顺序数组(一维数组)(可以识别多重键params.name)
     * @param string $field 字段
     * @param string $clear 是否舍弃没有匹配到的字段
     * @return array()
     */
    public static function customSort($arr=array(), $orderArr=array(),$clear=false){
        if(!$arr OR !$orderArr) return false;
        if(is_array($arr) or is_object($arr))
        foreach($orderArr as $key){
            $result[$key] = My::arr2var($arr,$key);
        }
        //是否重新拾回不在自定义排序数组中的数据
        if(is_array($arr) AND $clear==false)
        foreach($arr as $k=>$v){
            //$result为空或非数组时 $result不存在$arr[$k]值时
            if(empty($result) OR !is_array($result) OR !array_key_exists($k, $result))
                $result[$k] = $v;
        }
        return isset($result)?$result:array();
    }

    /**
     * 二维数组排序,根据某字段的值进行排序
     * @param array $arr 二维数组
     * @param array $key 排序的字段名
     * @param array $type 排序类型:asc->正序 / desc->反序
     * 注:两个字段同时进行排序时: array_multisort($arr1, SORT_ASC, $arr2, SORT_ASC, $result);
     */
    public static function array_sort(&$arr,$key,$type='asc'){
        if(!is_array($arr) OR !$arr)    return $arr;
        foreach($arr as $value) {
            $data[] = $value[$key];
        }
        if(strtolower($type)=='asc') $sort = SORT_ASC; else $sort = SORT_DESC;
        array_multisort($data, $sort, $arr);
        return $arr;
    }
    /**
     * 删除二维数组中的某字段(多个以逗号分割)
     * @param array $arr 二维数组
     * @param string $fields 字段(多个以逗号分割)
     */
    public static function array_delete_field($arr,$fields=''){
        if(!is_array($arr) OR $fields=='')
            return false;
        $fields = explode(',',$fields);
        foreach($arr as $key=>$value){
            if(is_array($fields))
            foreach($fields as $V){
                if(isset($arr[$key][$V]))
                    unset($arr[$key][$V]);
            }
        }
        return $arr;
    }


    /**
     * 引用缩略图(任意尺寸)
     * @param string $src 图片路径
     * @param int $width 宽 (当值为false或为空时不生成缩略图)
     * @param int $height 高 (当值为false或为空时不生成缩略图)
     * @param boolean $is_cut 生成的缩略图是否按指定尺寸(多余部分会被裁剪掉)
     * @return string 图片(缩略图)的路径
     */
    public static function thums($src='',$width='',$height='',$is_cut=false){
        //$self = __SHARE__.$src;
        $width = (int)$width;
        $height = (int)$height;
        //http现网路径时 直接返回
        $http = substr($src,0,4)=='http' ? true : false;
        //不存在http远程图片时,给默认图片的路径(太耗费性能，暂时注释掉)
        /*if($http AND !@Image::getImageInfo($src)){
            $src = "share/images/default.jpg";
            $http = false;
        }else */
        if(!$http AND (!file_exists(PUB_DIR.$src) OR empty($src))){
            $src = "share/images/default.jpg";
        }
        //!$width且!$height时代表不生成缩略图-直接返回图片原路径
        if(!$width AND !$height)
            return $http?$src:(__PUB__.$src);
        //是否裁切信息体现在缩略图文件名中
        $cutStr = ($is_cut==false)?'(no_cut)':'(is_cut)';
        //缩略图的web访问路径（用于返回图片src地址）
        $thumb_src = __PROJECT__.'Data/thumbnail/' . ($http?'_http_/'.md5($src):$src) . "_{$width}x{$height}{$cutStr}.jpg";
        //缩略图所在的磁盘物理路径
        $thumb_dir =   ROOT_DIR .'Data/thumbnail/' . ($http?'_http_/'.md5($src):$src) . "_{$width}x{$height}{$cutStr}.jpg";
        //缩略图文件不存在时，生成缩略图
        if(!file_exists($thumb_dir)){
            mk_dir(str_replace(strrchr($thumb_dir,'/'),'',$thumb_dir));//strrchr($dir,'/')为得到图片名称(/123.jpg)，然后将图片名称去掉再检测并生成缩略图路径
            try{
                @ini_set("memory_limit","256M");
                $image = new Image();
                $src_dir = $http?$src:(PUB_DIR.$src);
                //执行生成缩略图操作（Image::IMAGE_THUMB_SCALE：缩略图等比例缩放、Image::IMAGE_THUMB_CENTER：缩略图居中裁剪）
                @$image->open($src_dir)->thumb($width, $height, ($is_cut?Image::IMAGE_THUMB_CENTER:Image::IMAGE_THUMB_SCALE))->save($thumb_dir,null,85);
            }catch(Exception $e) {
                return "[".$e->getMessage().":{$src}]";//$thumb_dir
            }
        }
        return $thumb_src;
    }

    /**
     * 过滤数组中的空值()
     */
    public static function array_filter($array){
        $result = array();
        if(is_array($array))
        foreach($array as $k=>$a){  
            if($a!='')
                $result[$k]=$a;
        }
        return $result;
    }

    /**
     * 加密函数
     * 后台调用方法: My::encode();
     * smarty模板调用方法: {{'table=photo&field=ordering'|encode}}
     * @param string
     * @return string
     */
    public static function encode($str='', $operation='ENCODE', $key='dreamfans'){
        $result = ($str!='')?self::authcode($str, $operation, $key):'';
        $result = str_replace(array('+','/'),array("@B","@F"),$result);
        return $result;
    }
    /**
     * 解密函数
     * 后台调用方法: My::decode();
     * smarty模板调用方法: {{'SLKDU/U&*%ddsewe323'|decode}}
     * @param string
     * @return string
     */
    public static function decode($str='', $operation='DECODE', $key='dreamfans'){
        $str = str_replace(array('@B','@F'),array('+','/'),$str);
        $result = ($str!='')?self::authcode($str, $operation, $key):'';
        return $result;
    }
    /**
     * 加密/解密函数
     */
    private static function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
        $ckey_length = 4;
        $key = md5($key != '' ? $key : getglobal('authkey'));
        $keya = md5(substr($key, 0, 16));
        $keyb = md5(substr($key, 16, 16));
        $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
        $cryptkey = $keya.md5($keya.$keyc);
        $key_length = strlen($cryptkey);
        $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
        $string_length = strlen($string);
        $result = '';
        $box = range(0, 255);

        $rndkey = array();
        for($i = 0; $i <= 255; $i++) {
            $rndkey[$i] = ord($cryptkey[$i % $key_length]);
        }
        for($j = $i = 0; $i < 256; $i++) {
            $j = ($j + $box[$i] + $rndkey[$i]) % 256;
            $tmp = $box[$i];
            $box[$i] = $box[$j];
            $box[$j] = $tmp;
        }
        for($a = $j = $i = 0; $i < $string_length; $i++) {
            $a = ($a + 1) % 256;
            $j = ($j + $box[$a]) % 256;
            $tmp = $box[$a];
            $box[$a] = $box[$j];
            $box[$j] = $tmp;
            $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
        }
        if($operation == 'DECODE') {
            if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
                return substr($result, 26);
            } else {
                return '';
            }
        } else {
            return $keyc.str_replace('=', '', base64_encode($result));
        }
    }
        
    /**
     * 将数组中的某元素组合成一维数组
     * @param array $arr : 数组(2维数组)
     * @param mixed $field : 要组成一维数组的字段(如:id 或 array('id','name') 或 array('id','params.name'))
     */
    public static function arr2one($arr,$field='') {
        if(!is_array($arr))
            return false;
        if($field=='')
            return false;
        elseif(is_array($field)){
            $KKK=$field[0];
            $VVV=$field[1];
        }else{
            $KKK='';
            $VVV=$field;
        }
        $result = array();
        foreach($arr as $key=>$value){
            if($KKK=='')
                $result[]=My::arr2var($value,$VVV);
            else
                $result[My::arr2var($value,$KKK)]=My::arr2var($value,$VVV);
        }
        return $result;
    }
    /**
     * 得到数组中的某个字段值(主要是针对类似$result['params']['title']的变量<params.title>,当然没有.的也可以)
     * @param array $arr 数组
     * @param string $field 字段名(如:id  或  params.xxx)
     * @param string $default 默认值
     */
    public static function arr2var($arr,$field='',$default=''){
        if(!is_array($arr))
            return $default;//非数组时直接返回默认值
        $result = '';
        //字段格式为(params.xxx时)
        if(strpos($field,".")!==FALSE){
            $field = "['".str_replace(".", "']['", $field)."']";
            eval("@\$result = isset(\$arr{$field})?\$arr{$field}:'{$default}';");
        }else{
            $result = (isset($arr[$field]) AND $arr[$field]!='')?$arr[$field]:$default;
        }
        return $result;
    }
    /**
     * 循环输出N次某个字符串
     * smarty模板调用方法: {{5|forecho:'_'}}
     * @param string
     * @return string
     */
    public static function forecho($number=0,$str=''){
        $number = (int)$number;
        $html = '';
        if($number>0){
            for($i=0;$i<$number;$i++){
                $html .= $str;
            }
        }
        return $html;
    }

    /**
     * 从会话中获取用户信息
     * @param string $name 字段名(username / params.shop_params.title)
     * @return mixed
     */
    public static function user($name=''){
        //用户session
        if(!$name)
            $result = $_SESSION;
        elseif(isset($_SESSION))
            $result = My::arr2var($_SESSION,$name);
        else
            $result = '';
        return $result;
    }

    /**
     * 将源代码中的标签图片<img数据进行过滤(入库前准备)
     * 事务1: <img src="data:image/png;base64,....二进制数据保存为图片,并替换路径
     * 事务2: 处理本地图片链接前缀: <img src="/project/dreamfans/Public/替换成<img src="__PUB__
     */
    public static function encodeImg($content=''){
        if($content=='' OR !is_string($content))    return $content;
        //$content = My::base642image($content);
        $PUB_URL = __PUB__;
        //不存在字符$PUB_URL时直接返回
        if(strpos($content,$PUB_URL)===false)  return $content;
        $from = array(
                      'src="'.$PUB_URL,
                      "src='".$PUB_URL,
                      //"src=&quot;".$PUB_URL,
                      'src="http://'.$_SERVER ['HTTP_HOST'].$PUB_URL,
                      "src='http://".$_SERVER ['HTTP_HOST'].$PUB_URL,
                      //"src=&quot;http://".$_SERVER ['HTTP_HOST'].$PUB_URL,
                     );
        $to = array(
                    'src="{__PUB__}',
                    "src='{__PUB__}",
                    //'src=&quot;{__PUB__}',
                    'src="{__PUB__}',
                    "src='{__PUB__}",
                    //'src=&quot;{__PUB__}'
                   );
        $content = str_replace($from, $to, $content);
        return $content;
    }
    /**
     * 将源代码中的标签图片<img数据进行处理(显示前准备)
     * 事务1: 将<img src="__PUB__ 替换成 <img src="/project/dreamfans/Public/ 形式路径
     */
    public static function decodeImg($content=''){
        if($content=='' OR !is_string($content))  return $content;
        //不存在字符{__PUB__}时直接返回
        if(strpos($content,"{__PUB__}")===false)  return $content;
        $PUB_URL = "http://".$_SERVER ['HTTP_HOST'].__PUB__;
        $from = array(
                      "src=\"{__PUB__}",
                      "src='{__PUB__}",
                      //"src=&quot;{__PUB__}"
                     );
        $to = array(
                    "src=\"".$PUB_URL,
                    "src='".$PUB_URL,
                    //"src=&quot;".$PUB_URL
                   );
        $content = str_replace($from, $to, $content);
        return $content;
    }
    /**
     * base64格式图片数据另存为图片
     * 注:html代码中的这种格式: <img src="" alt="" />
     */
    public static function base642image($content=''){
        if($content=='' OR !is_string($content))  return $content;
        //不存在字符src="data:时直接返回
        if(!preg_match("/src=[\'\"]data:/U",$content))  return $content;
        //function __base642image__
        if(!function_exists('__base642image__')){
            function __base642image__($datas){
                $data = $datas[2];
                include_once(PUB_DIR.'share/plug/plupload/my.class.php');
                $data = base64_decode(str_replace(array('png;base64,','jpeg;base64,','jpg;base64,','gif;base64,'), '', $data));
                $fileName = md5($data).'.jpg';//图片文件名
                $path = getPath().'/'.$fileName;//图片文件路径
                $item = I('request.item','default');//item作为相册文件夹名称
                //不存在该图片时,保存图片到相册
                if(!file_exists($path)){
                    My::write($data,$path);
                    //保存到数据库
                    save2mysql($path, $fileName, $fileName,true);
                }
                return $datas[1].__PUB__.'share/images/'.$item.'/'.$fileName;
            }
        }
        $content = preg_replace_callback('/(<img.*?src=[\'\"])data:\s*image\/([^\"\']*)/', '__base642image__', $content);
        return $content;
    }


    /**
    * 判断变量是否是身份证
    */
    public static function is_card($id){
      $code = My::checkArg($id);
      if ($code === false) {
        return false;
      }
      // 查询cache
      if (isset ( self::$cache [ $id ] ) && self::$cache [$id] ['valid'] !== false) {
        return self::$cache [$id] ['valid'];
      } else {
        if (! isset ( self::$cache [ $id ] )) {
          self::$cache [$id] = array ();
        }
      }

      $addr = substr ( $code ['body'], 0, 6 );
      $birth = $code ['type'] === 18 ? substr ( $code ['body'], 6, 8 ) :
        substr ( $code ['body'], 6, 6 );
      $order = substr ( $code ['body'], - 3 );

      if(!(My::checkAddr($addr) && My::checkBirth($birth)&&My::checkOrder($order))) {
        self::$cache [$id] ['valid'] = false;
        return false; 
      }

      // 15位不含校验码，到此已结束
      if ($code ['type'] === 15) {
        self::$cache [$id] ['valid'] = true;
        return true;
      }

      /* 校验位部分 */

      // 位置加权
      $posWeight = array ();
      for($i = 18; $i > 1; $i --) {
        $wei = My::weight ( $i );
        $posWeight [$i] = $wei;
      }

      // 累加body部分与位置加权的积
      $bodySum = 0;
      $bodyArr = str_split( $code ['body'] );
      for($j = 0; $j < count ( $bodyArr ); $j ++) {
        $bodySum += (intval ( $bodyArr [$j], 10 ) * $posWeight [18 - $j]);
      }

      // 得出校验码
      $checkBit = 12 - ($bodySum % 11);
      if ($checkBit == 10) {
        $checkBit = 'X';
      } else if ($checkBit > 10) {
        $checkBit = $checkBit % 11;
      }
      // 检查校验码
      if ($checkBit != $code ['checkBit']) {
        self::$cache [$id] ['valid'] = false;
        return false;
      } else {
        self::$cache [$id] ['valid'] = true;
        return true;
      }
    }

    public static function checkArg($id) {
        $id = strtoupper ( $id );
        $code = null;
        if (strlen ( $id ) === 18) {
          // 18位
          $code = array (
              "body" => substr ( $id, 0, 17 ),
              "checkBit" => substr ( $id, - 1 ),
              "type" => 18
          );
        } else if (strlen($id) === 15) {
          // 15位
          $code = array (
              "body" => $id,
              "type" => 15
          );
        } else {
          return false;
        }
        return $code;
    }

    // 地址码检查
    public static function checkAddr($addr) {
      $addrInfo =My::getAddrInfo( $addr );
      return ($addrInfo === false ? false : true);
    }

    // 取得地址码信息
    public static function getAddrInfo($addr) {
      // 查询GB/T2260,没有引入GB2260时略过
      if (self::$GB2260 === null) {
        return $addr;
      }
      if (! isset ( self::$GB2260 [$addr] )) {
        // 考虑标准不全的情况，搜索不到时向上搜索
        $tmpAddr = substr ( $addr, 0, 4 ) . '00';
        if (! isset ( self::$GB2260 [$tmpAddr] )) {
          $tmpAddr = substr ( $addr, 0, 2 ) . '0000';
          if (! isset ( self::$GB2260 [$tmpAddr] )) {
            return false;
          } else {
            return self::$GB2260 [$tmpAddr] . '未知地区';
          }
        } else {
          return self::$GB2260 [$tmpAddr] . '未知地区';
        }
      } else {
        return self::$GB2260 [$addr];
      }
    }

    // 生日码检查
    public static function checkBirth($birth) {
      $year = $month = $day = 0;
      if (strlen ( $birth ) == 8) {
        $year = intval ( substr ( $birth, 0, 4 ) );
        $month = intval ( substr ( $birth, 4, 2 ) );
        $day = intval ( substr ( $birth, - 2 ) );
      } else if (strlen($birth) == 6) {
        $year = intval ( '19' + substr ( $birth, 0, 2 ) );
        $month = intval ( substr ( $birth, 2, 2 ) );
        $day = intval ( substr($birth, - 2 ) );
      } else {
        return false;
      }
      // TODO 是否需要判断年份
      /*
       * if( year<1800 ){ return false; }
       */
      // TODO 按月份检测
      if ($month > 12 || $month === 0 || $day > 31 || $day === 0) {
        return false;
      }

      return true;
    }

    // 顺序码检查
    public static function checkOrder($order) {
      // 暂无需检测
      return true;
    }
    // 加权
    public static function weight($t) {
      return pow ( 2, $t - 1 ) % 11;
    }
    // 随机整数
    public static function rand($max, $min = 1) {
      //return round ( rand(0, 1) * ($max - $min) ) + $min;
      return rand($min, $max);
    }
    // 数字补位
    public static function str_pad($str, $len = 2, $chr = '0', $right = false) {
      $str = strval($str);
      if (strlen ( $str ) >= $len) {
        return $str;
      } else {
        for($i = 0, $j = $len - strlen ( $str ); $i < $j; $i ++) {
          if ($right) {
            $str = $str . $chr;
          } else {
            $str = $chr . $str;
          }
        }
        return $str;
      }
    }


    /**
     * 判断日期格式是否正确
     * @param string $date 日期字符串
     * @param string $format 格式匹配(非必填),当有值时才进行格式匹配判断 (如:'Y-m-d')
     */
    public static function is_date($date='',$format=''){
        if(!$date) return false;
        $unixTime_1 = strtotime($date);
        if (!is_numeric($unixTime_1)) return false;
        $unixTime_2 = strtotime(date("Y-m-d H:i:s", $unixTime_1));
        if($unixTime_1 == $unixTime_2){
            //$date参数的日期格式正确,接下来匹配格式是否一致
            if($format!=''){
                if($date==Date::format($format,$date))
                    return true;
                else
                    return false;
            }else{
                return true;
            }
        }else{
            return false;
        }
    }

    /**
     * 判断是否符合变量命名规范
     * @param string $name 变量名
     * @return boolean
     */
    public static function is_var($varName){
        return preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_]*$/',$varName);
    }

    /**
     * 判断变量是否是ID (正整数)
     */
    public static function is_id($id=0){
        return (preg_match('/^[1-9][0-9]*$/', $id))?true:false;
    }
    
    /**
     * 是否是价格（浮点数）
     * @param string $string 待验证的字串
     * @return boolean
     */
    public static function is_price($number) {
        return 0 < (preg_match('/^(-?\d+)(\.\d+)?$/',$number) && $number>=0);
    }
    
    /**
     * 验证是否是合法的email
     * @param string $string 待验证的字串
     * @return boolean 如果是email则返回true，否则返回false
     */
    public static function is_email($string='') {
        return 0 < preg_match("/^\w+(?:[-+.']\w+)*@\w+(?:[-.]\w+)*\.\w+(?:[-.]\w+)*$/", $string);
    }

    /**
     * 判断字符串是否category表中的唯一名称
     */
    public static function is_item($item=''){
        if(!My::is_var($item))
            return false;
        $id = M('admin.category')->item2id($item);
        if(!My::is_id($id))
            return false;
        else
            return true;
    }
    /**
     * 判断表名是否存在
     * @param string $name 表名（不需要前缀，如：datas）
     */
    public static function is_table($name=''){
        if(!My::is_var($name))
            return false;
        return DB('')->is_table($name);
    }
    /**
     * 判断当前php环境是否是linux系统
     */
    public static function is_linux(){
        return (DIRECTORY_SEPARATOR=='\\')?false:true;
    }
    /**
     * 判断当前php环境是否是window系统
     */
    public static function is_windows(){
        return (DIRECTORY_SEPARATOR=='\\')?true:false;
    }
    /**
     * 判断是否为ajax请求
     */
    public static function is_ajax(){
        return (isset($_SERVER["HTTP_X_REQUESTED_WITH"]) && strtolower($_SERVER["HTTP_X_REQUESTED_WITH"])=="xmlhttprequest")?true:false;
    }
    /**
     * 判断是否为nginx服务器环境
     */
    public static function is_nginx(){
        return (strtolower(substr(I('server.SERVER_SOFTWARE'),0,5))=='nginx')?true:false;
    }
    /**
     * 判断是否为apache服务器环境
     */
    public static function is_apache(){
        return (strtolower(substr(I('server.SERVER_SOFTWARE'),0,6))=='apache')?true:false;
    }
    /**
     * 判断IP格式是否正确
     */
    public static function is_ip($string) {
        if(!is_string($string))
            return false;
        //ipv4
        $result1 = preg_match("/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/", $string);
        //ipv6
        $result2 = preg_match('/\A(?:(?:(?:[a-f0-9]{1,4}:){6}|
                                            ::(?:[a-f0-9]{1,4}:){5}|
                                            (?:[a-f0-9]{1,4})?::(?:[a-f0-9]{1,4}:){4}|
                                            (?:(?:[a-f0-9]{1,4}:){0,1}[a-f0-9]{1,4})?::(?:[a-f0-9]{1,4}:){3}|
                                            (?:(?:[a-f0-9]{1,4}:){0,2}[a-f0-9]{1,4})?::(?:[a-f0-9]{1,4}:){2}|
                                            (?:(?:[a-f0-9]{1,4}:){0,3}[a-f0-9]{1,4})?::[a-f0-9]{1,4}:|
                                            (?:(?:[a-f0-9]{1,4}:){0,4}[a-f0-9]{1,4})?::
                                        )(?:[a-f0-9]{1,4}:[a-f0-9]{1,4}|
                                            (?:(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}
                                            (?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])
                                        )|(?:(?:(?:[a-f0-9]{1,4}:){0,5}[a-f0-9]{1,4})?::[a-f0-9]{1,4}|
                                            (?:(?:[a-f0-9]{1,4}:){0,6}[a-f0-9]{1,4})?::
                                        )
                                    )\Z/ix', $string);
        return ($result1 OR $result2)?true:false;
    }
    /**
     * 判断参数是否为字符串
     * @param mixed $str 要判断的变量
     * @param string $filter 条件,多个逗号分隔,如"c,e,n"(如-> n:数字, c:中文, e:英文)
     * @param string $other 其它字符 (如:_*%)
     */
    public static function is_string($str='',$filter='',$other=''){
        if($str=='')
            return false;
        if(!is_numeric($str) AND !is_string($str))
            return false;
        //正由规则变量
        $match = '';
        //filter 条件
        if($filter!=''){
            $filter = My::explode(',',$filter);
            if(is_array($filter)){
                //英文字母
                if(in_array('e',$filter))
                    $match .= 'a-zA-Z';
                //数字
                if(in_array('n',$filter))
                    $match .= '0-9';
                //中文
                if(in_array('c',$filter))
                    $match .= '\x{4e00}-\x{9fa5}';
            }
        }
        //其它正则特殊字符
        if($other!='')
            $match .= $other;
        //验证正则规则
        if($match!='' AND !preg_match('/^['.$match.']+$/u', $str))
            return false;
        return true;
    }

    /**
     * 判断数据是否重复
     * @param string $table
     * @param string $param.id 数据id(用于编辑数据时排除该id号)
     * @param string $param.field 字段名(如:title/params.ID)
     * @param string $param.value 字段值(用来判断唯一性)
     * @param string $param.where SQL条件(如:`item`='menu') <字条串前面没有AND,函数内自动以AND连接where条件>
     */
    public static function is_only($table='',$param=''){
        if(!My::is_var($table)) return false;
        if(empty($param['field']) OR !My::is_var($table)) return false;
        if(!isset($param['value'])) return false;
        $where = isset($param['where'])?$param['where']:'1';
        $result = 0;
        //搜索params参数
        if(substr($param['field'],0,7)=='params.'){
            //排除id
            if(isset($param['id']) AND My::is_id($param['id']))
                $where .= " AND (A.id<{$param['id']} OR A.id>{$param['id']}) ";
            $key = str_replace('params.','',$param['field']);
            $result = DB('')->field('A.id')->join("#__{$table} as A INNER JOIN #__{$table}_params as B ON B.`key`='{$key}' AND B.`value`='{$param['value']}' AND A.id=B.idid")->where($where)->group("A.id")->select();
            //echo DB('')->getLastSql();
            $result = count($result);
        }
        //搜索主表参数
        else{
            //排除id
            if(isset($param['id']) AND My::is_id($param['id']))
                $where .= " AND id<{$param['id']} AND id>{$param['id']} ";
            //field=>value
            $where.= " AND `{$params['field']}`='{$param['value']}'";
            $result = DB($table)->where($where)->find();
        }
        return $result;
    }

    /**
     * 验证是否是手机号码
     * 国际区号-手机号码
     * @param string $number 待验证的号码
     * @return boolean 如果验证失败返回false,验证成功返回true
     */
    public static function is_tel($number) {
        return 0 < preg_match('/^(0|86|17951)?(13[0-9]|15[012356789]|17[0-9]|18[0-9]|14[57])[0-9]{8}$/', $number);
    }
    
    
    /**
     * 验证是否是固话或手机号码
     * 区号-电话号码  或 国际区号-手机号码
     * @param string $number 待验证的号码
     * @return boolean 如果验证失败返回false,验证成功返回true
     */
    public static function is_tel2($number) {
        return 0 < preg_match('/^(0[0-9]{2,3}\-)?([2-9][0-9]{6,7})+(\-[0-9]{1,4})?$|(^(0|86|17951)?(13[0-9]|15[012356789]|17[0-9]|18[0-9]|14[57])[0-9]{8}$)/', $number);
    }

    /**
     * 判断是否属手机
     */
    public static function is_mobile(){
        $user_agent = $_SERVER['HTTP_USER_AGENT'];
        $mobile_agents = Array("240x320","acer","acoon","acs-","abacho","ahong","airness","alcatel","amoi","android","anywhereyougo.com","applewebkit/525","applewebkit/532","asus","audio","au-mic","avantogo","becker","benq","bilbo","bird","blackberry","blazer","bleu","cdm-","compal","coolpad","danger","dbtel","dopod","elaine","eric","etouch","fly ","fly_","fly-","go.web","goodaccess","gradiente","grundig","haier","hedy","hitachi","htc","huawei","hutchison","inno","ipad","ipaq","ipod","jbrowser","kddi","kgt","kwc","lenovo","lg ","lg2","lg3","lg4","lg5","lg7","lg8","lg9","lg-","lge-","lge9","longcos","maemo","mercator","meridian","micromax","midp","mini","mitsu","mmm","mmp","mobi","mot-","moto","nec-","netfront","newgen","nexian","nf-browser","nintendo","nitro","nokia","nook","novarra","obigo","palm","panasonic","pantech","philips","phone","pg-","playstation","pocket","pt-","qc-","qtek","rover","sagem","sama","samu","sanyo","samsung","sch-","scooter","sec-","sendo","sgh-","sharp","siemens","sie-","softbank","sony","spice","sprint","spv","symbian","tablet","talkabout","tcl-","teleca","telit","tianyu","tim-","toshiba","tsm","up.browser","utec","utstar","verykool","virgin","vk-","voda","voxtel","vx","wap","wellco","wig browser","wii","windows ce","wireless","xda","xde","zte");
        $is_mobile = false;
        foreach ($mobile_agents as $device) {
            if (stristr($user_agent, $device)) {
                $is_mobile = true;
                break;
            }
        }
        return $is_mobile;
    }
    
    /**
     * 判断页面是否用微信浏览器打开的
     */
    public static function is_weixin(){
        $user_agent = $_SERVER['HTTP_USER_AGENT'];
        if (strpos($user_agent, 'MicroMessenger') === false) {
            return false;
        } else {
            return true;
            // 获取版本号
            //preg_match('/.*?(MicroMessenger\/([0-9.]+))\s*/', $user_agent, $matches);
            //echo '<br>Version:'.$matches[2];
        }
    }

    /**
     * 发送邮件
     * @DEMO -> $sendok = My::sendMail(array('title'=>'邮件标题','content'=>$this->fetch('sendmail')));   if($sendok==true) $this->ajaxReturn(200,'发送成功!');
     * string $param['username'] 发件人的邮箱用户名(非必需)
     * string $param['password'] 发件人的邮箱用户密码(非必需)
     * string $param['host'] 指定的SMTP服务器地址(非必需)
     * array $param['receiver'] 收件人地址(多个用数组)(非必需)
     * string $param['title'] 邮箱标题
     * string $param['content'] 邮箱内容
     * string $param['attachments'] 附件地址(非必需)
     */
    public static function sendMail($param=''){
        //print_r($param);
        include_once(PLUG."phpmailer/phpmailer.class.php");
        $mail = new PHPMailer();
        //设置使用SMTP
        $mail->IsSMTP();
        //设置为安全验证方式
        $mail->SMTPAuth = true;
        //解决邮件发送乱吗
        $mail->CharSet = "utf-8";
        //set word wrap to 50 characters
        $mail->WordWrap = 80;
        //语言包
        $mail->SetLanguage('cn',PLUG.'phpmailer/language/');
        //SMTP 发邮件人的用户名
        $mail->Username = isset($param['username'])?$param['username']:C('email_username');
        //SMTP 密码
        $mail->Password = isset($param['password'])?$param['password']:C('email_password');
        //指定的SMTP服务器地址 (smtp.qq.com)
        $mail->Host = isset($param['host'])?$param['host']:(C('email_host')?C('email_host'):str_replace("@","smtp.",strrchr($mail->Username,'@')));//默认取$params['host']，如没有则取C('email_host')参数，再没有就取$emailType['host']参数
        //来自发件人
        $mail->From = isset($param['username'])?$param['username']:C('email_username');
        //发件人
        $mail->FromName = isset($param['fromname'])?$param['fromname']:C('email_fromname');
        if(isset($param['receiver']) AND is_array($param['receiver'])){
            foreach($param['receiver'] as $value)
                $mail->AddAddress($value);//添加收件人地址,多个收件人重启添加就行 //$mail->AddAddress("123@qq.com","收件人名称");
        }elseif($email_receipt = C('email_receipt')){
            $email_receipt = explode(',',$email_receipt);
            if(is_array($email_receipt))
                foreach($email_receipt as $value)
                    $mail->AddAddress($value);
        }
        //加附件
        if(isset($param['attachments']))
            $mail->AddAttachment($param['attachments']);//$mail->AddAttachment("/tmp/image.jpg", "new.jpg");//附件，也可选加命名附件
        //设置邮件格式为 HTML
        $mail->IsHTML(true);
        //标题
        $mail->Subject = $param['title'];
        //内容
        $mail->Body  = $param['content'];
        //附加内容
        //$mail->AltBody = "This is the body in plain text for non-HTML mail clients";
        $ok = $mail->Send();
        if($ok){//发送成功,返回1
            return true;
        }else{
            return $mail->ErrorInfo;
        }       
    }

    /**
     * implode 函数 重写
     */
    public static function implode($separator='',$array=''){
        if(!is_array($array))
            return $array;
        return implode($separator,$array);
    }
    /**
     * explode 函数 重写
     */
    public static function explode($separator='',$string=''){
        if(is_array($string) OR !$string)
            return $string;
        return explode($separator,$string);
    }

    /**
     * 分页类
     * @param int $total 总条数
     * @param array  $param.pagesize 每页条数
     * @param string $param.otherParam 附加URL参数[array('title'=>'abc','id'=>100)]
     * @param string $param.buttonNum 分页控件的数字按钮个数(默认10个)
     * @param string $param.header 基础信息(默认:<span class="disabled">共%TOTAL_ROW%条记录 %NOW_PAGE%/%TOTAL_PAGE%页</span>)
     * @param string $param.prev 上一页的文字显示（默认：'上一页'）
     * @param string $param.next 下一页的文字显示（默认：'下一页'）
     * @param string $param.first 首页的文字显示（默认：'首页'）
     * @param string $param.last 尾页的文字显示（默认：'尾页'）
     * @param string $param.theme 定制风格 （默认：'%HEADER% %FIRST% %UP_PAGE% %LINK_PAGE% %DOWN_PAGE% %END%'）
     * 注：分页的参数名称默认为:page，当一个页面同时有多个分页模块时可以定义不同的C('VAR_PAGE')值用于区分
     */
    public static function page($total=0,$param=''){
        //总数
        if(!My::is_id($total)) return false;
        //每页显示条目
        $pagesize = (isset($param['pagesize']) AND My::is_id($param['pagesize']))?$param['pagesize']:10;
        //session优先
        $pagesize = (My::is_id(My::user('pagesize')))?My::user('pagesize'):$pagesize;
        //当前页数
        $now = My::is_id(I('request.page'))?I('request.page'):1;
        //当前页码大于1时,当前页刚好没数据则显示上一页
        if($now>1 AND ($pagesize*($now-1)>=$total)) $now--;
        $page = new Page($total, $pagesize, My::arr2var($param,'otherParam')); //(总数, 每页显示条目, 附加URL参数)
        // 分页栏每页显示的页数
        $page->rollPage = isset($param['buttonNum']) ? $param['buttonNum'] : 10;
        //config设置初始化基础参数
        $param['header'] = isset($param['header'])?$param['header']:'<span class="disabled">共%TOTAL_ROW%条记录 %NOW_PAGE%/%TOTAL_PAGE%页</span>';  $page->setConfig('header',$param['header']);
        $param['prev'] = isset($param['prev'])?$param['prev']:'上一页';  $page->setConfig('prev',$param['prev']);
        $param['next'] = isset($param['next'])?$param['next']:'下一页';  $page->setConfig('next',$param['next']);
        $param['first'] = isset($param['first'])?$param['first']:'首页';  $page->setConfig('first',$param['first']);
        $param['last'] = isset($param['last'])?$param['last']:'尾页';  $page->setConfig('last',$param['last']);
        $param['theme'] = isset($param['theme'])?$param['theme']:'%HEADER% %FIRST% %UP_PAGE% %LINK_PAGE% %DOWN_PAGE% %END% '.(strtolower(APP_NAME)=='admin' ? '%PAGESIZE%' : '');
        $page->setConfig('theme',$param['theme']);
        $sql = DB('')->getLastSql();//当前分页的sql
        //assign
        //$this->assign("pagenav",$page->show());//分页
        //$this->assign("page_info",My::encode("page={$now}&pagesize={$pagesize}&sql={$sql}"));//当前分页信息(目前用于拖动保存排序)

        $result['page'] = $now;//当前页数
        $result['pagesize'] = $pagesize;//每页显示条目
        $result['total'] = $total;//总数
        $result['limits'] = (($now-1)*$pagesize).",".$pagesize;
        $result['html'] = $page->show();
        return $result;
    }

    /**
     * 添加和获取页面Trace记录
     * @param string $value 变量
     * @param string $label 标签
     * @param string $level 日志级别
     * @param boolean $record 是否记录日志
     * @return void
     */
    public static function trace($value='[dream]',$label='',$level='DEBUG',$record=false) {
        static $_trace = array();
        if('[dream]' === $value){ // 获取trace信息
            return $_trace;
        }else{
            $info   =   ($label?$label.':':'').print_r($value,true);
            $level  =   strtoupper($level);
            
            if((defined('IS_AJAX') && IS_AJAX) || !C('SHOW_PAGE_TRACE')  || $record) {
                Log::record($info,$level,$record);
            }else{
                if(!isset($_trace[$level]) || count($_trace[$level])>C('TRACE_MAX_RECORD')) {
                    $_trace[$level] =   array();
                }
                $_trace[$level][]   =   $info;
            }
        }
    }
    
    /**
     * object转换为数组函数
     */
    public static function obj2arr($array){
        if(is_object($array)){
            $array = (array)$array;
        }
        if(is_array($array)){
            foreach($array as $key=>$value){
                $array[$key] = My::obj2arr($value);
            }
        }
        return $array;
    }
    
    /**
     * 用缩略图替换文章中的图片路径
     * @param string $content 内容
     * @return string
     *
     */
    public static function img_replace($content){
        //function __img_replace__
        if(!function_exists('__img_replace__')){
            function __img_replace__($datas){
                return $datas[1].My::thums($datas[2],640);
            }
        }
        //return
        return  preg_replace_callback('/(<img.*?src=[\"\'])([^\"\']*)/', '__img_replace__', $content);
    }
    
    /**
     * 日志生成函数
     * @param array $oldData 更改前的旧数组数据
     * @param array $newData 为新表单提交的数组数据
     * @param array $fieldData 比较变化字段对应的中文信息 如：如array("name"=>"姓名","email"=>"邮箱") 
     */
    public static function changeLog($oldData,$newData,$fieldData){
        if(!$oldData)
            return '';
        if(!$fieldData)
            return '';
        $date = '['.date('Y-m-d H:i:s').'] ';
        $logs = $date;
        foreach ($fieldData as $key => $value) {
            if(My::arr2var($oldData,$key)!=My::arr2var($newData,$key))
                $logs .= $value.'修改成功(由“'.My::arr2var($oldData,$key).'”修改为“'.My::arr2var($newData,$key).'”)，';
        }
        if($logs==$date)
            return '';
        return $logs.'操作员：'.My::id2field('user',My::user('userid'),'name').'['.My::user('username').']。';
    }

    /**
     * 生成订单号
     */
    public static function createOrder(){
        return substr(time(), 0).sprintf("%03d", rand(1,999));
    }
    
    /**
     * 跳转函数(兼容函数)
     * by huanran.zhao
     */
    public static function ajaxReturn($statusCode, $message, $data='') {
        $jsonData = array(
            'statusCode' => $statusCode,
            'message' => $message,
            'data' => $data  
        );
        exit(json_encode($jsonData));
    }

    /**
     * json_encode ：不转义中文字符和\/的 json 编码方法
     * @param array $arr 待编码数组
     * @return string
     */
    public static function encodeJson($arr='') {
        if(!is_array($arr))
            return $arr;
        if(!function_exists('encodeHtml')){
            function encodeHtml(&$str){
                $str = My::encodeHtml($str,true);
            }
        }
        array_walk_recursive($arr,'encodeHtml');
        if(version_compare(PHP_VERSION, '5.4.0', '<')) {
            $str = str_replace ( "\\/", "/", json_encode ( $arr ) );
            $search = "#\\\u([0-9a-f]{4})#ie";
            if (strpos ( strtoupper(PHP_OS), 'WIN' ) === false) {
                $replace = "iconv('UCS-2BE', 'UTF-8', pack('H4', '\\1'))";//LINUX
            } else {
                $replace = "iconv('UCS-2', 'UTF-8', pack('H4', '\\1'))";//WINDOWS
            }
            $result = preg_replace($search, $replace, $str);
        }
        //PHP 5.4+ 有自带的不编码中文函数
        else{
            $result = json_encode($arr, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        }
        return $result;
    }
    
    /**
     * json_decode ：json解码
     * @param string $str 等解码字符串
     * @return array
     */
    public static function decodeJson($str=''){
        if(!$str OR !is_string($str)) return $str;
        return json_decode($str,true);
    }

    /**
     * 去除字符串两边指定字符
     * @param string $str 要处理的字符串
     * @param string $symbol 要过滤的指定字符
     */
    public static function trim($str, $symbol=''){
        $symbol = quotemeta($symbol);//预定义的字符自动加反斜杠：. \ + * ? [ ] ^ $ ( )
        //默认去除字符串两边空格
        if($symbol=='')
            $mode = '/(^\s*)|(\s*$)/';
        //过滤自定义指定字符
        else
            $mode = "/(^$symbol*)|($symbol*$)/";
        //echo $mode;die;
        return preg_replace($mode,'',$str);
    }
    /**
     * 去除字符串左边指定字符
     * @param string $str 要处理的字符串
     * @param string $symbol 要过滤的指定字符
     */
    public static function ltrim($str,$symbol=''){
        $symbol = quotemeta($symbol);//预定义的字符自动加反斜杠：. \ + * ? [ ] ^ $ ( )
        //默认去除左边空格
        if($symbol=='')
            $mode = '/(^\s*)/';
        //过滤自定义指定字符
        else
            $mode = "/(^$symbol*)/";
        return preg_replace($mode,'',$str);
    }
    /**
     * 去除字符串右边指定字符
     * @param string $str 要处理的字符串
     * @param string $symbol 要过滤的指定字符
     */
    public static function rtrim($str,$symbol=''){
        $symbol = quotemeta($symbol);//预定义的字符自动加反斜杠：. \ + * ? [ ] ^ $ ( )
        //默认去除右边空格
        if($symbol=='')
            $mode = '/(\s*$)/';
        //过滤自定义指定字符
        else
            $mode = "/($symbol*$)/";
        return preg_replace($mode,'',$str);
    }

    /**
     * 计算两个地图的经纬度的距离
     * @param string $location1 经纬度1
     * @param string $location2 经纬度2
     * @param string $unit 单位
     */
    public static function distance($location1, $location2, $unit = 'M') {
        if($location1==$location2) return 'true';
        if($location1=='' OR $location2=='') return false;
        $location1 = explode(',', $location1);
        $location2 = explode(',', $location2);
        $lon1 = $location1[0];
        $lat1 = $location1[1];
        $lon2 = $location2[0];
        $lat2 = $location2[1];
        $theta = $lon1 - $lon2;  
        $dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) +  cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta));  
        $dist = acos($dist);  
        $dist = rad2deg($dist);  
        $miles = $dist * 60 * 1.1515;  
        $unit = strtoupper($unit);    
        if ($unit == "M") {  
            $dis = ($miles * 1609.344);  
        }elseif ($unit == "K") {  
            $dis = ($miles * 1.609344);  
        }elseif($unit == "N") {  
            $dis = ($miles * 0.8684);  
        }else{  
            $dis =  $miles;  
        } 
        return ceil($dis);  
    }
    
    /**
     * 分页统计函数
     * @param string $total_sql SQL语句
     */
    public static function sql2count($total_sql){
        if($total_sql=='')
            return 0;
        $total = DB('')->query("select count(1) as `count_num` from (".$total_sql.") as `count_table`");
        return My::arr2var($total,'0.count_num',0);
    }
    
    /**
     * 把ueditor上传的文件从临时目录移动指定的地方
     */
    public static function dealUeditor($content=''){
        if($content=='' OR !is_string($content))  return $content;
        //没有Ueditor的临时文件时返回
        if(!preg_match("/src=[\'\"][\/\w]*\/Data\/MyCache\/ueditor\//U",$content))  return $content;
        //function __dealUeditor__
        if(!function_exists('__dealUeditor__')){
            function __dealUeditor__($datas){
                include_once(PUB_DIR.'share/plug/plupload/my.class.php');
                $fileName = $datas[2];//图片文件名
                $path = getPath().'/'.$fileName;//图片文件路径
                $item = I('request.item','default');//item作为相册文件夹名称
                $subdir = isset($_REQUEST['subdir'])?('/'.str_replace('|', '/', I('request.subdir'))):'';//子目录
                //缩略图处理
                $cacheFile = "../Data/MyCache/ueditor/".$datas[2];
                $thum = My::thums($cacheFile,800,600,false);
                if(__PROJECT__=='/')
                    $thum = ROOT_DIR.$thum;
                    else
                        $thum = str_replace(__PROJECT__,ROOT_DIR,$thum);
                        //移动到指定目录
                        $dir = dirname($path);
                        if(!is_dir($dir))
                            mk_dir($dir);
                            rename($thum,$path);
    
                            //保存到数据库
                            save2mysql($path, $fileName, $fileName,true);
                            return $datas[1].__PUB__.'share/images/'.$item.$subdir.'/'.$fileName;
            }
        }
        $content = preg_replace_callback('/(<img.*?src=[\'\"])[\/\w]*\/Data\/MyCache\/ueditor\/([^\"\']*)/', '__dealUeditor__', $content);
        return $content;
    }
    
    
    
    /**
     * 判断参数是否为IDs
     * @param mixed $str 要判断的变量
     */
    public static function is_ids($str=''){
        if($str=='')
            return false;
            //验证正则规则
            if(!preg_match('/^\d+(\,\d+)*$/u', $str))
                return false;
                return true;
    }

    /**
     * 处理SEO信息
     */
    public static function deal_seo(&$data){
        //自动提取SEO关键字(seo_keywords)
        if(empty($data['params']['seo_keywords'])){//SEO关键字为空时自动提取
            $keywords = '';
            try{ $sw = new SplitWord(); }
            catch (Exception $e){ $this->ajaxReturn(300, $e->getMessage()); }
            $sw->SetSource($data['title']);
            $sw->StartAnalysis();
            $title_indexs = $sw->GetFinallyIndex();
            $sw->SetSource(isset($data['content'])?strip_tags($data['content']):'');
            $sw->StartAnalysis();
            $content_indexs = $sw->GetFinallyIndex();
            if(is_array($title_indexs) && is_array($content_indexs)){
                $all_indexs = array_merge($title_indexs, $content_indexs);
                foreach ($all_indexs as $k=>$v){
                    if(strlen($keywords.$k) > 60) break;
                    elseif(strlen($k) <= 3) continue;
                    else $keywords .= $k.',';
                }
                $data['params']['seo_keywords'] = rtrim($keywords, ',');
            }
        }
        //自动提取SEO摘要(seo_description)
        if(empty($data['params']['seo_description'])){
            $data['params']['seo_description'] = mb_substr(My::deal_space(trim(isset($data['content'])?strip_tags($data['content']):'')), 0, 80, 'utf-8');
        }
    }
    
    
    /**
     * 处理空格
     * 1、&nbsp;和中空空格换成英文空格
     * 2、去掉换行符、去掉制表符
     * 3、去掉首尾空格
     * 4、连续两个以上的空格转为1个空格
     */
    public static function deal_space($str){
        if($str=='')
            return $str;
        $str = str_replace(array("&nbsp;","　"), " ", $str);
        $str = trim($str);
        $str = preg_replace(array(
            "/[\t]*/i",
            "/[\n]*/i",
            "/[\r]*/i",
            "/([\s])[\s]+/i",
        ), array(
            "",
            "",
            "",
            " ",
        ), $str);
        return $str;
    }
}